package bv

//Vector the vector
type Vector struct {
	data [][]float64
	axis int
}

//Matrix the matrix
type Matrix struct {
	data []interface{}
	dim  []int
}

//MakeVector make the vector
func MakeVector(dim int, value ...float64) *Vector {
	v := &Vector{}
	v.Make(dim, value...)
	return v
}

//MakeVectorByArray make the vector by array
func MakeVectorByArray(dim int, values []float64) *Vector {
	v := &Vector{}
	v.Make(dim, values...)
	return v
}

//MakeVectorByIntArray make the vector for int array
func MakeVectorByIntArray(dim int, value ...int) *Vector {
	d := make([]float64, len(value))
	for i := 0; i < len(value); i++ {
		d[i] = float64(value[i])
	}
	v := &Vector{}
	v.Make(dim, d...)
	return v
}

//Make make the vector
func (V *Vector) Make(dim int, value ...float64) {
	if dim == 0 {
		V.axis = 0
		d := make([]float64, len(value))
		copy(d, value)
		V.data = append(V.data, d)
	} else {
		V.axis = 1
		for i := 0; i < len(value); i++ {
			V.data = append(V.data, make([]float64, 1))
			V.data[i][0] = value[i]
		}
	}
}

//T the vector.T
func (V *Vector) T() *Vector {
	v := &Vector{}
	if V.axis == 0 {
		v.axis = 1
		for i := 0; i < len(V.data[0]); i++ {
			v.data = append(v.data, make([]float64, 1))
			v.data[i][0] = V.data[0][i]
		}
	} else {
		v.axis = 0
		d := []float64{}
		for i := 0; i < len(V.data); i++ {
			d = append(d, V.data[i][0])
		}
		v.data = append(v.data, d)
	}
	return v
}

//Add the vector add
func (V *Vector) Add(v *Vector) *Vector {
	var v2 *Vector
	if V.axis+v.axis != 1 {
		v2 = v
	} else {
		v2 = v.T()
	}
	var d []float64
	if V.axis == 0 {
		d = make([]float64, len(V.data[0]))
		for i := 0; i < len(V.data[0]); i++ {
			d[i] = V.data[0][i] + v2.data[0][i]
		}
	} else {
		d = make([]float64, len(V.data))
		for i := 0; i < len(V.data); i++ {
			d[i] = V.data[i][0] + v2.data[i][0]
		}
	}
	v3 := &Vector{}
	v3.Make(v.axis, d...)
	return v3
}

//Sub the vector Sub
func (V *Vector) Sub(v *Vector) *Vector {
	var v2 *Vector
	if V.axis+v.axis != 1 {
		v2 = v
	} else {
		v2 = v.T()
	}
	var d []float64
	if V.axis == 0 {
		d = make([]float64, len(V.data[0]))
		for i := 0; i < len(V.data[0]); i++ {
			d[i] = V.data[0][i] - v2.data[0][i]
		}
	} else {
		d = make([]float64, len(V.data))
		for i := 0; i < len(V.data); i++ {
			d[i] = V.data[i][0] - v2.data[i][0]
		}
	}
	v3 := &Vector{}
	v3.Make(v.axis, d...)
	return v3
}

//Dot the vector dot
func (V *Vector) Dot(v *Vector) *Vector {
	var v2 *Vector
	if V.axis+v.axis != 1 {
		v2 = v
	} else {
		v2 = v.T()
	}
	var d []float64
	if V.axis == 0 {
		d = make([]float64, len(V.data[0]))
		for i := 0; i < len(V.data[0]); i++ {
			d[i] = V.data[0][i] * v2.data[0][i]
		}
	} else {
		d = make([]float64, len(V.data))
		for i := 0; i < len(V.data); i++ {
			d[i] = V.data[i][0] * v2.data[i][0]
		}
	}
	v3 := &Vector{}
	v3.Make(v.axis, d...)
	return v3
}

//Div the vector div
func (V *Vector) Div(v *Vector) *Vector {
	var v2 *Vector
	if V.axis+v.axis != 1 {
		v2 = v
	} else {
		v2 = v.T()
	}
	var d []float64
	if V.axis == 0 {
		d = make([]float64, len(V.data[0]))
		for i := 0; i < len(V.data[0]); i++ {
			d[i] = V.data[0][i] / v2.data[0][i]
		}
	} else {
		d = make([]float64, len(V.data))
		for i := 0; i < len(V.data); i++ {
			d[i] = V.data[i][0] / v2.data[i][0]
		}
	}
	v3 := &Vector{}
	v3.Make(v.axis, d...)
	return v3
}
